# 聚类,无监督分类

import pandas as pd
import scipy.cluster.hierarchy as sch
import pylab as plt
import numpy as np
from sklearn.cluster import KMeans
import Determined_K as DK
import Image
from sklearn.cluster import DBSCAN


# 参数解释
# 注意：数据的行是样本指标，列是样本，不要搞反了否则需要转置
# 一键化处理聚类
# k-means,系统层次聚类
def K_Means_start(InputData=None, ClassFication_Nums=2, title=''):
    """
    :param InputData: 要聚类的矩阵DataFrame
    :param ClassFication_Nums: 数据分成的类数
    :param title: 附加的最前面的标题
    :param DrawJudgePicture: 是否绘制判断最佳聚类点的图,参考脚本Determined_K
    :return:
    labels：聚类结果
    centers：聚类的几何中心
    """
    # 确定K均值聚类最佳确定聚类的个数
    # 判断K的取值
    DK.Judge_K(InputData, title)
    print('分类数目为', ClassFication_Nums, ',正在执行最终的K均值算法......')
    # 使用K均值算法求解聚类模型
    result = KMeans(ClassFication_Nums).fit(InputData)
    # 提取标签
    labels = result.labels_ + 1
    # 每一行是一个聚类中心
    centers = result.cluster_centers_
    return labels, centers


def DB_Scan_start(data, EPS: float = 0.5, Minpts: int = 5):
    """
    :param EPS:领域范围
    :param Minpts: 形成核心点的领域最小点的数目
    :return: 返回的predict为每个样本预测的类型
    """
    # 初始化DBSCAN类
    # metric距离度量
    # n_jobs并行计算的核心数目
    db_scan = DBSCAN(eps=EPS, min_samples=Minpts)
    predict = db_scan.fit_predict(X=data)
    # predict为每个样本预测的类型
    return predict


def Hierarchical_Clustering_start(InputData:pd.DataFrame,t=4.5,title:str='',SystemMethod='single', SystemMetric='euclidean'):
    """
    系统层次聚类，这里默认的是将每行元素聚类
    :param InputData: DataFrames输入矩阵
    :param title: 标题
    :param t:分类依据的类外间距，决定了分类的结果
    :param SystemMethod:系统聚类方法,默认最小距离法single
    :param SystemMetric:数据计算距离的方法,默认欧几里得距离euclidean
    :return:
    """
    # 系统聚类
    # 获取第一列名字
    print('正在进行系统聚类......')
    # 系统聚类
    # 生成点与点之间的距离矩阵, 这里用的欧氏距离: euclidean
    # X：根据什么来聚类，这里结合总体情况 Gross 与平均情况 Avg 两者
    # InputData,根据哪些列来计算距离
    disMat = sch.distance.pdist(X=InputData, metric='euclidean')
    z = sch.linkage(disMat, method='ward')
    labels = sch.fcluster(z, t=t, criterion='distance')  # 聚类，这里t阈值的选择很重要
    plt.figure()
    sch.dendrogram(z, labels=InputData.AREA.tolist())
    plt.title(title + '系统聚类结果')
    print('系统聚类成功!!!')
    return labels

